package traceHandler

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"goproject/commonType"
	"goproject/logger"
	"goproject/requestProxy"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"strings"
	"time"
)

/*
1. 发起目标请求
2. 从jaeger获取目标请求的trace数据
3. 从jaeger获取目标请求的span数据
4. 根据目标请求的traceId和应用信息请求request proxy
5. 处理数据格式
*/
func convertMapStringToInterface(input map[string]string) map[string]interface{} {
	output := make(map[string]interface{})
	for key, value := range input {
		output[key] = value
	}
	return output
}

func convertMapStringToJSON(input map[string]string) (string, error) {
	jsonData, err := json.Marshal(input)
	if err != nil {
		return "", err
	}
	return string(jsonData), nil
}

func convertMapInterfaceToJSON(input map[string]interface{}) (string, error) {
	jsonData, err := json.Marshal(input)
	if err != nil {
		return "", err
	}
	return string(jsonData), nil
}

func GetTraceData(ctx context.Context, req commonType.SelectedReq) (commonType.TraceTree, error) {
	log := logger.GetLogger()
	log.Info("开始获取追踪数据")

	// 发起 req 请求
	// 记录请求开始时间
	startTime := time.Now()
	log.Infof("请求开始时间: %v", startTime)

	_, err := SendRequest(ctx, req)
	if err != nil {
		log.Errorf("发送请求时出错: %v", err)
		return commonType.TraceTree{}, err
	}

	// sleep 1s
	time.Sleep(1 * time.Second)

	// 记录请求结束时间
	endTime := time.Now()
	log.Infof("请求结束时间: %v", endTime)

	// 请求 jaeger 获取 trace 数据
	traceData, err := GetTraceDataFromJaeger(ctx, startTime, endTime, req.ServiceName+"."+req.Namespace)
	if err != nil {
		log.Errorf("从Jaeger获取追踪数据时出错: %v", err)
		return commonType.TraceTree{}, err
	}

	// 请求 jaeger 获取 podnames
	podInfoList, err := GetPodNamesFromJaeger(traceData)
	if err != nil {
		log.Errorf("从Jaeger获取Pod名称时出错: %v", err)
		return commonType.TraceTree{}, err
	}

	// 根据podNames 请求 request proxy
	traceRequestList, err := requestProxy.GetRequestData(ctx, podInfoList, req.Namespace)
	if err != nil {
		log.Errorf("从Request Proxy获取数据时出错: %v", err)
		return commonType.TraceTree{}, err
	}

	// 需要单独处理front-end
	frontEnd := commonType.TraceRequestList{
		PodName: GetPodNameByPrefix(traceData, "front-end"), // podname需要进行抽取
		TraceRequests: []commonType.Request{
			{
				URL:    req.URL,
				Method: req.Method,
				Header: convertMapStringToInterface(req.Header),
				Data:   req.Data,
			},
		},
	}

	traceRequestList = append(traceRequestList, frontEnd)
	// 构造树
	traceTree := buildTraceTree(traceData)
	// 将 traceTree 写入 trace.json 文件
	// 获取当前目录
	currentDir, err := os.Getwd()
	file, err := os.Create(currentDir + "/controller/traceRequestList.json")
	if err != nil {
		log.Errorf("创建文件时出错: %v", err)
		return commonType.TraceTree{}, err
	}
	defer file.Close()

	encoder := json.NewEncoder(file)
	encoder.SetIndent("", "  ") // 美化输出
	if err := encoder.Encode(traceRequestList); err != nil {
		log.Errorf("写入文件时出错: %v", err)
		return commonType.TraceTree{}, err
	}
	log.Info("成功将追踪数据写入 traceRequestList.json 文件")

	file, err = os.Create(currentDir + "/controller/traceTree.json")
	encoder = json.NewEncoder(file)
	encoder.SetIndent("", "  ") // 美化输出
	if err := encoder.Encode(traceTree); err != nil {
		log.Errorf("写入文件时出错: %v", err)
		return commonType.TraceTree{}, err
	}
	log.Info("成功将追踪数据写入 traceTree.json 文件")

	file, err = os.Create(currentDir + "/controller/traceData.json")
	encoder = json.NewEncoder(file)
	encoder.SetIndent("", "  ") // 美化输出
	if err := encoder.Encode(traceData); err != nil {
		log.Errorf("写入文件时出错: %v", err)
		return commonType.TraceTree{}, err
	}
	log.Info("成功将追踪数据写入 traceData.json 文件")

	// 合并数据
	mergeTraceRequestLists(&traceTree, traceRequestList)
	return traceTree, nil
}

func GetPodNameByPrefix(traceItem commonType.TraceItem, prefix string) string {
	for _, span := range traceItem.Spans {
		for _, tag := range span.Tags {
			if tag.Key == "node_id" {
				// 判断tag.value里是否包含prefix
				if strings.Contains(tag.Value, prefix) {
					return extractPodName(span)
				}
			}
		}
	}
	return ""
}

// SendRequest 发送HTTP请求并返回响应
func SendRequest(ctx context.Context, req commonType.SelectedReq) (string, error) {
	// 获取全局日志处理器实例
	log := logger.GetLogger()

	// 构建查询参数字符串
	params := url.Values{}
	for key, value := range req.Params {
		params.Add(key, fmt.Sprintf("%v", value))
	}
	queryParams := params.Encode()

	// 拼接查询参数到URL
	fullURL := req.URL
	if queryParams != "" {
		fullURL += "?" + queryParams
	}

	// 转换数据为 JSON 字符串
	convertedData, err := convertMapInterfaceToJSON(req.Data)
	if err != nil {
		log.Fatalf("转换数据时出错: %v", err)
	}

	// 创建请求体
	requestBody := bytes.NewBufferString(convertedData)
	log.Infof("创建请求体: %s", convertedData)

	// 创建HTTP请求
	httpReq, err := http.NewRequestWithContext(ctx, req.Method, fullURL, requestBody)
	if err != nil {
		log.Errorf("创建HTTP请求时出错: %v", err)
		return "", err
	}
	log.Infof("创建了HTTP请求: %s %s", req.Method, fullURL)

	// 添加请求头
	for key, value := range req.Header {
		httpReq.Header.Set(key, value)
		log.Infof("添加请求头: %s: %s", key, value)
	}

	// 发送HTTP请求
	client := &http.Client{}
	log.Info("发送HTTP请求...")
	resp, err := client.Do(httpReq)
	if err != nil {
		log.Errorf("发送HTTP请求时出错: %v", err)
		return "", err
	}
	defer func() {
		log.Info("关闭响应体...")
		resp.Body.Close()
	}()

	// 读取响应数据
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Errorf("读取响应数据时出错: %v", err)
		return "", err
	}
	log.Infof("收到响应: %s", resp.Status)

	return string(body), nil
}

// 根据startTime 与 endTime 向jaeger请求获取trace数据
// http://49.232.65.15:8083/jaeger/api/traces?end=1716016972081000&limit=20&lookback=1h&maxDuration&minDuration&service=orders.sock-shop&start=1716013372081000
// getJaegerData 从 Jaeger API 获取 trace 数据
func GetTraceDataFromJaeger(ctx context.Context, startTime, endTime time.Time, service string) (commonType.TraceItem, error) {
	// 休眠2s
	time.Sleep(5 * time.Second) // 休眠 2 秒

	log := logger.GetLogger()

	baseURL := "http://localhost:8083/jaeger/api/traces"
	params := url.Values{}
	params.Add("end", fmt.Sprintf("%d", endTime.UnixNano()/1e3))
	params.Add("limit", "10")
	params.Add("lookback", "5m")
	params.Add("maxDuration", "")
	params.Add("minDuration", "")
	params.Add("service", service)
	params.Add("start", fmt.Sprintf("%d", startTime.UnixNano()/1e3))
	fullURL := fmt.Sprintf("%s?%s", baseURL, params.Encode())

	req, err := http.NewRequestWithContext(ctx, http.MethodGet, fullURL, nil)
	if err != nil {
		log.Errorf("创建HTTP请求时出错: %v", err)
		return commonType.TraceItem{}, err
	}

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		log.Errorf("发送HTTP请求时出错: %v", err)
		return commonType.TraceItem{}, err
	}
	defer func() {
		log.Info("关闭响应体...")
		resp.Body.Close()
	}()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Errorf("读取响应数据时出错: %v", err)
		return commonType.TraceItem{}, err
	}
	var result struct {
		Data []commonType.TraceItem `json:"data"`
	}
	err = json.Unmarshal(body, &result)
	if err != nil {
		log.Errorf("解析JSON数据时出错: %v", err)
		return commonType.TraceItem{}, err
	}

	if len(result.Data) == 0 {
		log.Warn("未找到任何追踪数据")
		return commonType.TraceItem{}, fmt.Errorf("no trace items found")
	}

	// 找到具有最大跨度数的追踪项
	maxSpansItem := result.Data[0]
	if len(result.Data) != 1 {
		for _, item := range result.Data[1:] {
			if len(item.Spans) > len(maxSpansItem.Spans) {
				maxSpansItem = item
			}
		}
	}
	return maxSpansItem, nil
}

// extractPodNames 提取 podname 并去重
func GetPodNamesFromJaeger(traceItem commonType.TraceItem) ([]commonType.PodInfo, error) {
	log := logger.GetLogger()
	podInfoMap := make(map[string]*commonType.PodInfo)
	spans := traceItem.Spans

	// 过滤出有效的 span（请求的发起者）
	for _, span := range spans {
		var isOutbound bool
		for _, tag := range span.Tags {
			if tag.Key == "upstream_cluster.name" && strings.Contains(tag.Value, "outbound") {
				isOutbound = true
				break
			}
		}
		if !isOutbound {
			continue
		}

		// 查找对应 podName
		targetSpan := commonType.Span{}
		for _, innerspan := range spans {
			for _, ref := range innerspan.References {
				if ref.RefType == "CHILD_OF" && ref.SpanID == span.SpanID {
					targetSpan = innerspan
					break
				}
			}
		}
		// 处理podname
		for _, tag := range targetSpan.Tags {
			if tag.Key == "node_id" {
				parts := strings.Split(tag.Value, "~")
				if len(parts) >= 3 {
					podPart := strings.Split(parts[2], ".")
					if len(podPart) >= 1 {
						podName := podPart[0]
						if podInfo, exists := podInfoMap[podName]; exists {
							podInfo.SpanList = append(podInfo.SpanList, span.SpanID)
						} else {
							podInfoMap[podName] = &commonType.PodInfo{
								PodName:  podName,
								SpanList: []string{span.SpanID},
							}
						}
					}
				}
			}
		}
	}

	podInfoList := make([]commonType.PodInfo, 0, len(podInfoMap))
	for _, podInfo := range podInfoMap {
		podInfoList = append(podInfoList, *podInfo)
	}

	log.Infof("找到的Pod信息: %v", podInfoList)
	return podInfoList, nil
}

func extractPodName(span commonType.Span) string {
	for _, tag := range span.Tags {
		if tag.Key == "node_id" {
			parts := strings.Split(tag.Value, "~")
			if len(parts) >= 3 {
				podPart := strings.Split(parts[2], ".")
				if len(podPart) >= 1 {
					return podPart[0]
				}
			}
		}
	}
	return ""
}

func extractServiceName(span commonType.Span, processes map[string]commonType.Process) string {
	process, exists := processes[span.ProcessID]
	if exists {
		parts := strings.Split(process.ServiceName, ".")
		if len(parts) >= 1 {
			return parts[0]
		}
	}
	return ""
}

func extractTraceRequest(span commonType.Span) commonType.Request {
	var url, method string
	headers := make(map[string]interface{})
	data := make(map[string]interface{})

	for _, tag := range span.Tags {
		switch tag.Key {
		case "http.url":
			url = tag.Value
		case "http.method":
			method = tag.Value
		default:
			if strings.HasPrefix(tag.Key, "http.headers.") {
				headers[strings.TrimPrefix(tag.Key, "http.headers.")] = tag.Value
			} else if strings.HasPrefix(tag.Key, "http.data.") {
				data[strings.TrimPrefix(tag.Key, "http.data.")] = tag.Value
			}
		}
	}

	return commonType.Request{
		URL:    url,
		Method: method,
		Header: headers,
		Data:   data,
	}
}

func buildTraceTree(traceItem commonType.TraceItem) commonType.TraceTree {

	log := logger.GetLogger()
	log.Info("开始构建追踪树")

	nodeMap := make(map[string]*commonType.Node)
	edges := []commonType.Edge{}
	nodeID := 0

	for _, span := range traceItem.Spans {

		podName := extractPodName(span)
		if isRequestSpan(span) && !strings.Contains(podName, "front-end") {
			continue
		}
		traceRequest := extractTraceRequest(span)
		node, exists := nodeMap[podName]
		if exists {
			node.TraceRequest = append(node.TraceRequest, traceRequest)
		} else {
			serviceName := extractServiceName(span, traceItem.Processes)
			node = &commonType.Node{
				ID:           nodeID,
				PodName:      podName,
				ServiceName:  serviceName,
				TraceRequest: []commonType.Request{traceRequest},
			}
			nodeMap[podName] = node
			nodeID++
		}
	}
	nodes := make([]commonType.Node, 0, len(nodeMap))
	for _, node := range nodeMap {
		nodes = append(nodes, *node)
	}

	for _, span := range traceItem.Spans {
		podName1 := extractPodName(span)
		if podName1 == "" {
			continue
		}
		id1 := nodeMap[podName1].ID

		for _, ref := range span.References {
			for _, parentSpan := range traceItem.Spans {
				if parentSpan.SpanID == ref.SpanID {
					podName2 := extractPodName(parentSpan)
					if podName2 == "" {
						continue
					}
					id2 := nodeMap[podName2].ID

					// Check if edge already exists
					exists := false
					for _, edge := range edges {
						if edge.Source == id2 && edge.Target == id1 {
							exists = true
							break
						}
					}
					if !exists {
						edges = append(edges, commonType.Edge{Source: id2, Target: id1})
					}
				}
			}
		}
	}

	traceTree := commonType.TraceTree{Nodes: nodes, Edges: edges}
	return traceTree
}

// 判断一个span是否为请求端span
func isRequestSpan(span commonType.Span) bool {
	var isOutbound bool
	for _, tag := range span.Tags {
		if tag.Key == "upstream_cluster.name" && strings.Contains(tag.Value, "outbound") {
			isOutbound = true
			break
		}
	}
	return isOutbound
}

func mergeTraceRequestLists(traceTree *commonType.TraceTree, traceRequestLists []commonType.TraceRequestList) {
	log := logger.GetLogger()
	log.Info("开始合并追踪请求列表")

	for _, traceRequestList := range traceRequestLists {

		for i := range traceTree.Nodes {
			node := &traceTree.Nodes[i]
			if node.PodName == traceRequestList.PodName {
				if strings.Contains(traceRequestList.PodName, "front-end") {
					log.Infof("过滤的 podname: %s", traceRequestList.PodName)
					node.TraceRequest = traceRequestList.TraceRequests
					break
				}
				for _, traceRequest := range traceRequestList.TraceRequests {
					//merged := false
					// user的处理出现了些问题
					for j, existingRequest := range node.TraceRequest {
						if strings.Contains(existingRequest.URL, traceRequest.URL) && existingRequest.Method == traceRequest.Method {
							// Merge Headers
							for key, value := range traceRequest.Header {
								existingRequest.Header[key] = value
							}
							// Merge Data
							for key, value := range traceRequest.Data {
								existingRequest.Data[key] = value
							}
							node.TraceRequest[j] = existingRequest
							//merged = true
							break
						}
					}

					//if !merged {
					//	node.TraceRequest = append(node.TraceRequest, traceRequest)
					//}
				}
			}
		}
	}
}
